var express = require('express');
var xml2json = require('xml2js').parseString;
var iconv = require('iconv-lite');
var router = express.Router();
var {
  adminDao,
  logDao,
  playerDao,
  raidDao,
  save,
  backupList,
  backup,
  restore,
  getUserByReq
} = require('../data')
var mq = require('mysql-queries').init({
  host: 'localhost',
  port: 3306,
  user: 'root',
  password: 'root',
  database: 'realmd'
});

var crypto = require('crypto');
var svgCaptcha = require('svg-captcha');
var moment = require('moment');
const DT_FORMAT = 'YYYY-MM-DD HH:mm:ss'
let dateFormat = function (dt) {
  return moment(new Date(dt)).format(DT_FORMAT)
}
var path = require('path')
var fs = require('fs');
var multer = require('multer');
const uploadFolder = path.join('public','temp')

function mkdirsSync(dirpath, mode) {
  try {
    if (!fs.existsSync(dirpath)) {
      let pathtmp;
      dirpath.split(/[/\\]/).forEach(function (dirname) { //这里指用/ 或\ 都可以分隔目录  如  linux的/usr/local/services   和windows的 d:\temp\aaaa
        if (pathtmp) {
          pathtmp = path.join(pathtmp, dirname);
        } else {
          pathtmp = dirname;
        }
        if (!fs.existsSync(pathtmp)) {
          if (!fs.mkdirSync(pathtmp, mode)) {
            return false;
          }
        }
      });
    }
    return true;
  } catch (e) {
    console.log("create director fail! path=" + dirpath + " errorMsg:" + e);
    return false;
  }
}

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    let path = `${uploadFolder}/`
    mkdirsSync(path)
    cb(null, path)
  },
  filename: function (req, file, cb) {
    let date = new Date;
    let year = date.getFullYear(),
      month = ('0' + (date.getMonth() + 1)).slice(-2),
      day = ('0' + date.getDate()).slice(-2),
      hour = ('0' + date.getHours()).slice(-2),
      minute = ('0' + date.getMinutes()).slice(-2),
      second = ('0' + date.getSeconds()).slice(-2)
    cb(null, `${year+month+day+hour+minute+second}.${file.originalname.split('.').pop()}`)
  }
})

var upload = multer({
  storage: storage
})

router.get('/', function (req, res, next) {
  res.status(404);
  res.end();
});

router.get('/loginCaptcha', function (req, res) {
  var captcha = svgCaptcha.create();
  req.session.loginCaptcha = captcha.text;
  // console.log('生成验证码：' + req.session.loginCaptcha)
  res.type('svg');
  res.status(200).send(captcha.data);
  res.end();
});

router.post('/login', function (req, res, next) {
  var {
    username = '', password = '', code = ''
  } = req.body
  if (!username || !password || !code) {
    return res.json({
      status: 1,
      msg: '提交数据不正确，请检验！'
    })
  }

  // console.log('校验验证码：' + req.session.loginCaptcha)
  if (code.toUpperCase() != req.session.loginCaptcha.toUpperCase()) {
    req.session.loginCaptcha = Math.random() + '';
    return res.json({
      status: 2,
      msg: '验证码不正确'
    })
  }

  password = crypto.createHash('md5').update(password).digest('hex').toUpperCase();
  // console.log(password)
  //pizi dkpmaster001 D95E36B59CEFAE7C7D42DB5A23E0E961
  //kaka kakaduoduodezhanghao 35CF1EA7B59DE3EAE6DF67FF12F2A49B
  //jacky administrator 200CEB26807D6BF99FD6F4F0D1CA54D4
  var user = adminDao.check(username, password)
  if (user) {
    user.token = crypto.createHash('md5').update(Math.random() + '').digest('hex').toUpperCase();
    user.lastLoginAt = +new Date
    save(true);

    res.json({
      status: 0,
      msg: '登录成功',
      data: {
        "username": user.username, //用户名
        "token": user.token, //凭据
        "level": user.level //级别
      }
    })
  } else {
    req.session.loginCaptcha = Math.random() + '';
    res.json({
      status: 1,
      msg: '用户名/密码不正确',
      data: {}
    })
  }
});

router.post('/adminList', function(req, res, next) {
  adminDao.search({
    ...req.body
  }).then(({data})=>{
    res.json({
      status: 0,
      data
    })
  })
});

router.post('/adminSetLevel', function(req, res, next) {
  let user = getUserByReq(req);
  let {username,level} = req.body;
  if(user.username == username){
    return res.json({
      status: -1,
      msg: '不能修改自己的权限等级'
    })
  }

  let admin = adminDao.find(username);
  if(admin){
    admin.level = parseInt(level);
    save(true);
    res.json({
      status: 0
    })
  }
})

router.post('/adminResetPwd', function(req, res, next) {
  let {username} = req.body;
  let admin = adminDao.find(username)
  if(admin){
    let newPwd = '7788414'
    let pwd = crypto.createHash('md5').update(newPwd).digest('hex').toUpperCase();
    admin.password = pwd;
    admin.token = (''+Math.random()).split('.')[1];
    save(true);

    res.json({
      status: 0,
      data: {
        newPwd: newPwd
      }
    })
  }else{
    res.json({
      status: -1,
      msg: '该用户不存在或者已被删除'
    })
  }
})

router.post('/adminChangePwd', function(req, res, next) {
  let {password, newPassword} = req.body;
  let admin = getUserByReq(req)
  if(admin){
    let pwd = crypto.createHash('md5').update(password).digest('hex').toUpperCase();
    if(adminDao.check(admin.username,pwd)){
      admin.password = crypto.createHash('md5').update(newPassword).digest('hex').toUpperCase();
      save(true);
      res.json({
        status: 0
      })
    }else{
      res.json({
        status: -1,
        msg: '当前密码不正确!'
      })
    }
  }
})

router.post('/adminRemove', function(req, res, next) {
  let {username} = req.body;
  let user = adminDao.find(username);
  let admin = getUserByReq(req);
  if(admin && user){
    if(admin.username == user.username || admin.level < user.level){
      res.json({
        status: -1,
        msg: '不能操作自己以及权限级别比自己高的用户'
      })
    }else{
      adminDao.delete(username);
      save(true);
      res.json({status: 0})
    }
  }else{
    res.json({
      status: -1,
      msg: '没有找到该用户'
    })
  }
})

router.post('/adminAdd', function(req, res, next) {
  let {username, password, level} = req.body;
  let admin = getUserByReq(req)
  if(admin){
    if(adminDao.find(username)){
      res.json({
        status: -1,
        msg: '该账号已存在，请检查'
      })
    }else{
      password = crypto.createHash('md5').update(password).digest('hex').toUpperCase();
      let admin = {
        username, 
        password, 
        level: parseInt(level),
        token: '',
        lastLoginAt: null
      }

      adminDao.add(admin).then(_=>{
        save(true);      
        res.json({
          status: 0
        })
      }).catch(e=>{
        res.json({
          status: -1,
          msg: '保存失败'
        })
      })      
    }
  }
})

//添加角色
router.post('/createPlayer', function(req, res, next) {
  var {
    name,
    race,
    class: clazz,
    level,
    linkedTo,
    scores,
    joinTime
  } = req.body;
  if (!name) {
    return res.json({
      status: 1,
      msg: '提交数据不正确，请检验！'
    })
  }

  playerDao.add({
    name,
    race,
    class: clazz,
    level,
    scores: {
      MC: 0,
      BWL: 0,
      TAQ: 0,
      NAXX: 0,
      TAQ2: 0,
      NAXX2: 0
    },
    joinTime: joinTime || new Date()
  }).then(r => {
    let queue = [];
    Object.keys(scores).forEach(instance=>{
      let score = scores[instance];
      if (!isNaN(score) && score != 0) {
        queue.push(playerDao.changeScore([name], {
          raid: '--',
          scoreType: instance,
          score,
          reason: 'other',
          reasonNote: '初次添加'
        }))
      }
    })

    Promise.all(queue).then(_ => {
      save(true);
      res.json({
        status: 0,
        msg: '添加成功！'
      })
    })
  }, err => {
    res.json({
      status: 3,
      msg: err.msg
    })
  })
});

router.post('/modifyPlayer', function(req, res, next) {
  var {
    name,
    race,
    class: clazz,
    level,
    linkedTo
  } = req.body;
  playerDao.update({
    name,
    race,
    class: clazz,
    level,
    linkedTo
  }).then(r => {
    res.json({
      status: 0
    })
  }, err => {
    res.json({
      status: 3,
      msg: err.msg
    })
  })
});

router.post('/modifyDkp', function(req, res, next) {
  let {
    player,
    scores
  } = req.body;
  if (player) {
    let queue = [];
    Object.keys(scores).forEach(instance=>{
      let score = scores[instance];
      if (score.value) {
        queue.push(playerDao.changeScore([player], {
          scoreType: instance,
          ...score,
          score: score.value
        }))
      }
    });

    Promise.all(queue).then(r => {
      res.json({
        status: 0
      })
    }, err => {
      res.json({
        status: 2,
        msg: '保存失败'
      })
    })
  } else {
    reject({
      code: 3,
      msg: '缺少必要参数'
    })
  }
});

router.post('/parseRaidXml', upload.single('file'), function(req, res, next) {
  var file = req.file
  var charset = req.body.charset
  let filePath = path.resolve(file.path)
  let content = fs.readFileSync(filePath)
  if(charset == 'source'){
    let raid = null;
    try{
      raid = JSON.parse(content)
      fs.unlink(filePath, function (err) {
        res.json({
          status: 0,
          data: raid
        })
      })
    }catch(e){
      fs.unlink(filePath, function (err) {
        res.json({
          stauts: 101,
          msg: '导入失败，文件格式不正确'
        })
      })
    }
  }else{
    content = iconv.decode(content, charset);

    xml2json(content, (err, result) => {
      if (err) {
        return res.json({
          status: 4,
          msg: '导入失败，DKP字符串格式不正确！'
        })
      }

      let info = result.RaidInfo;
      let zone = info.zone ? info.zone[0] : '野外BOSS';
      let raid = {
        key: info.key[0],
        start: dateFormat(info.start[0]),
        end: dateFormat((info.end && info.end[0]) || new Date),
        zone,
        mode: ['黑翼之巢','安其拉神殿','纳克萨玛斯'].includes(zone) ? 'byItem' : 'byBoss'
      };

      let raidPlayers = Object.values(info.PlayerInfos[0]).map(player => {
        // console.log(JSON.stringify(player[0]))
        player = {
          name: player[0].name[0],
          race: player[0].race[0],
          level: (player[0].level && player[0].level[0]) || 60,
          class: player[0].class[0]
        };
        //新参加活动的角色要先添加到角色列表
        if (!playerDao.exists(player.name)) {
          //查找该角色的参加活动时间
          let joinTime = Object.values(info.Join[0]).find(o => o[0].player[0] == player.name)[0].time[0] || Date.now();
          joinTime = dateFormat(joinTime)
          playerDao.add({
            ...player,
            scores: {
              MC: 0,
              BWL: 0,
              TAQ: 0,
              NAXX: 0,
              TAQ2: 0,
              NAXX2: 0
            },
            joinTime
          })
        } else {
          playerDao.update(player, true)
        }

        return player;
      });

      raid.players = {};
      raidPlayers.forEach(p => {
        raid.players[p.name] = {
          join: Object.values(info.Join[0])
            .filter(o => o[0].player[0] == p.name)
            .map(o => +new Date(o[0].time[0])),
          leave: Object.values(info.Leave[0])
            .filter(o => o[0].player[0] == p.name)
            .map(o => +new Date(o[0].time[0]))
        };
      });

      raid.playerRelation = {}
      playerDao.playerRelation().forEach(o => {
        raid.playerRelation[o.name] = {
          race: o.race,
          class: o.class,
          linkedTo: o.linkedTo
        }
      })

      raid.bossKills = Object.values(info.BossKills[0]).map(o => ({
        name: o[0].name[0],
        time: dateFormat(o[0].time[0])
      }));

      raid.loot = Object.values(info.Loot[0])
        .map(o => ({
          itemName: o[0].ItemName[0],
          itemID: o[0].ItemID[0],
          class: o[0].Class[0],
          subClass: o[0].SubClass[0],
          color: '#' + o[0].Color[0].slice(2),
          costs: o[0].Costs ? +o[0].Costs[0] : 0,
          count: +o[0].Count[0],
          player: o[0].Player[0],
          time: dateFormat(o[0].Time[0]),
          zone: o[0].Zone[0],
          boss: o[0].Boss[0],
          note: o[0].Note[0]
        }))
        .filter(
          o => ["#ffffff", "#1eff00", "#0070dd"].indexOf(o.color) < 0
        );
      // console.log(filePath)
      fs.unlink(filePath, function (err) {
        res.json({
          status: 0,
          data: raid
        })
      })
    });
  }
})

router.post('/importDkpData', function(req, res, next) {
  let {
    data
  } = req.body;
  let folder = path.join('public','dkpFiles','sources')
  mkdirsSync(folder)
  let date = new Date;
  let year = date.getFullYear(),
    month = ('0' + (date.getMonth() + 1)).slice(-2),
    day = ('0' + date.getDate()).slice(-2),
    hour = ('0' + date.getHours()).slice(-2),
    minute = ('0' + date.getMinutes()).slice(-2),
    second = ('0' + date.getSeconds()).slice(-2)
  let fileName = `${year+month+day+hour+minute+second}.json`
  let filePath = path.join(path.resolve(folder), fileName)

  fs.writeFileSync(filePath, JSON.stringify(data))

  let info = data
  let raid = {
    key: info.key,
    start: info.start,
    source: fileName,
    end: info.end,
    zone: info.zone,
    players: info.players,
    loot: info.loot,
    bossKills: info.bossKills,
    mode: info.mode,
    scoreType: info.scoreType
  };

  //常规扣分
  info.downItem.filter(o => o.player.score > 0).forEach(o => {
    playerDao.changeScore([o.player.name], {
      raid: raid.key,
      scoreType: raid.scoreType,
      name: o.player.name,
      itemID: o.itemID,
      itemName: o.itemName,
      score: -Math.abs(o.player.score),
      reason: 'loot',
      reasonNote: '',
      color: o.color,
      clazz: o.class,
      subClass: o.subClass,
      count: o.count,
      boss: o.boss,
      zone: o.zone,
      note: o.note,
      time: o.time
    })
  })

  //非常规扣分
  info.additionalDownItem.forEach(item => {
    item.players.filter(o => o.score > 0).forEach(o => {
      playerDao.changeScore([o.name], {
        raid: raid.key,
        scoreType: raid.scoreType,
        name: o.name,
        itemName: '',
        score: -Math.abs(o.score),
        reason: item.reason,
        reasonNote: item.reasonNote,
        color: '',
        clazz: '',
        subClass: '',
        count: '',
        boss: '',
        zone: raid.zone,
        note: raid.note,
        time: raid.end
      })
    })
  })

  //常规加分
  info.raiseItem.forEach(item => {
    item.players.filter(o => o.score > 0).forEach(o => {
      playerDao.changeScore([o.name], {
        raid: raid.key,
        scoreType: raid.scoreType,
        itemName: '',
        name: o.name,
        score: o.score,
        reason: raid.mode == 'byBoss' ? 'boss' : 'item',
        reasonNote: '',
        color: '',
        clazz: '',
        subClass: '',
        count: '',
        boss: item.name,
        zone: raid.zone,
        note: raid.note,
        time: item.time
      })
    })
  })

  //非常规加分
  info.additionalRaiseItem.forEach(item => {
    let time = '';
    if(item.reason=='collect'){
      time = raid.start
    }else if(item.reason=='dismiss'){
      time = raid.end
    }else {
      time = raid.end
    }

    item.players.filter(o => o.score > 0).forEach(o => {
      playerDao.changeScore([o.name], {
        raid: raid.key,
        scoreType: raid.scoreType,
        name: o.name,
        itemName: '',
        score: o.score,
        reason: item.reason,
        reasonNote: item.reasonNote,
        color: '',
        clazz: '',
        subClass: '',
        count: '',
        boss: '',
        zone: raid.zone,
        note: raid.note,
        time
      })
    })
  })

  raid.hasFirstDown = info.additionalRaiseItem.some(o=>o.reason=="firstDown")

  return raidDao.add(raid).then(r => {
    try {
      // save();
      res.json({
        status: 0
      })
    } catch (e) {
      console.log(e)
      res.json({
        status: 2,
        msg: '保存失败'
      })
    }
  }, err => {
    console.log(err)
    res.json({
      status: 2,
      msg: '保存失败'
    })
  });
})

router.post('/saveToFile', function(req, res, next) {
  save()
  res.json({status:0})
})

router.post('/backup', function(req, res, next) {
  backup()
  res.json({status:0})
})

router.post('/backupList', function(req, res, next) {
  let result = backupList(req.body.pageNo, req.body.pageSize);
  if(!result.list){
    res.json({
      status: 2,
      msg: '查询备份记录时出现错误！'
    })
  }else{
    res.json({
      status: 0,
      data: {
        ...result
      }
    })
  }
})

router.post('/restore', function(req, res, next) {
  restore(req.body.backupPoint)
  res.json({status:0})
})

router.post('/removePlayer', function(req, res, next) {
  playerDao.remove(req.body.name)
  res.json({status:0})
})

//管理员列表
router.get('/list', function(req, res, next) {
  var {
    username,
    level,
    pageNo = 1,
    pageSize,
    sort,
    order
  } = req.query, result = [];

  adminDao.search({
    username,
    level,
    pageNo,
    pageSize,
    sort,
    order
  }).then(data => {
    res.json({
      status: 0,
      msg: '加载成功',
      data: data.data
    })
  }, err => {
    res.json({
      status: err.code,
      msg: err.msg
    })
  })
});

router.post('/getBoardMsg',function(req,res,next){
  res.json({
    status: 0,
    data: {
      boardMsg: playerDao.getBoardMsg()
    }
  })
})

router.post('/setBoardMsg',function(req,res,next){
  playerDao.setBoardMsg(req.body.boardMsg)
  res.json({
    status: 0
  })
})

router.post('/gameAccountResetPwd', function(req, res, next) {
  var {username} = req.body
  var newPwd = '123456';
  newPwd = newPwd.toUpperCase();
  username = username.toUpperCase();
  mq.query('select id from account where username=?', [username], function(err, rst) {
    if (err){
      res.json({
        status: -1,
        msg: '数据库连接失败'
      })
    } else if (rst.length === 0) {
        res.json({
          status: -1,
          msg: '该用户不存在'
        })
    } else {
      //8301316D0D8448A34FA6D0C6BF1CBFA2B4A1A93A
      const password = crypto.createHash('sha1').update(username + ':' + newPwd).digest('hex');
      mq.query('update account set v="0", s="0", sha_pass_hash = ? where username= ?', [password, username], function (err) {
        if (err) {
          res.json({
            status: -1,
            msg: '数据库连接失败'
          })
        } else {
          res.json({
            status: 0,
            data: {
              newPwd
            },
            msg: ''
          })
        }
      })
    }
  })
})


module.exports = router;